package com.launch.timer;

import javax.security.auth.callback.LanguageCallback;
import java.util.Set;

/**
 * @author ennian
 * 存储延时任务的桶 LaunchWheelTimeOut
 *  LaunchWheelTimeOut 本身充当链表节点
 */
public class LaunchWheelBucket {
   private LaunchWheelTimeout head ; //链表头节点
   private LaunchWheelTimeout tail ; //链表尾节点
    /**
     *  添加延时任务
     * @param timeout
     */
   public void addTimeOut(LaunchWheelTimeout timeout){
        timeout.bucket = this ;
       if (head == null) {
           //链表首位节点 ， 就一个
           head = tail = timeout;
       } else {
           //尾节点替换
           tail.next = timeout;
           timeout.prev = tail;
           tail = timeout;
       }
   }

    /**
     *
     * @param deadline 终止时间
     */
    public void expireTimeouts(long deadline) {
        // 头节点
        LaunchWheelTimeout timeout = head;

        while (timeout != null) {
            boolean remove = false;
            // 如果不到一圈了
            if (timeout.remainingRounds <= 0) {
                if (timeout.deadline <= deadline) {
                    timeout.expire();
                } else {
                    // 演示任务槽位异常
                    throw new IllegalStateException(String.format(
                            "timeout.deadline (%d) > deadline (%d)", timeout.deadline, deadline));
                }
                remove = true;
            } else if (timeout.isCancelled()) {
                remove = true;
            } else {
                timeout.remainingRounds --;
            }
            // 存储next引用 .
            LaunchWheelTimeout next = timeout.next;
            if (remove) {
                remove(timeout);
            }
            timeout = next;
        }
    }

    /**
     *  移除timeout
     * @param timeout
     */
    public void remove(LaunchWheelTimeout timeout) {
        // 当前next引用指向 timeout.next
        LaunchWheelTimeout next = timeout.next;
        // 删除当前的timeout
        if (timeout.prev != null) {
            timeout.prev.next = next;
        }
        if (timeout.next != null) {
            timeout.next.prev = timeout.prev;
        }
        if (timeout == head) {
            if (timeout == tail) {
                tail = null;
                head = null;
            } else {
                head = next;
            }
        } else if (timeout == tail) {
            // 如果是尾节点引用指向前一个节点
            tail = timeout.prev;
        }
        //  gc 回收  timeout首尾引用为空
        timeout.prev = null;
        timeout.next = null;
        timeout.bucket = null;
    }

    /**
     * 清除当前桶，返回所有没有被取消或者过期的延时任务
     */
    public void clearTimeOuts(Set<TimeOut> set) {
        for (;;){
             LaunchWheelTimeout launchWheelTimeout = this.pollTimeOut();
             if (launchWheelTimeout == null) return;
             if (launchWheelTimeout.cancel() || launchWheelTimeout.isExpired()){
                 return;
             }
             set.add(launchWheelTimeout) ;
        }
    }


    /**
     *  吐出头节点 timeout
     *  @return
     */
    private LaunchWheelTimeout pollTimeOut(){
        // 链表头节点引用
        LaunchWheelTimeout head = this.head;
        if (head == null) return null ;
        // 链表下一个节点
        LaunchWheelTimeout next = head.next;
        if (next == null) tail = this.head = null ;
        else {
            //头节点引用指向 next
            this.head = next ;
            //next 前一个节点置空
            next.prev = null ;
        }
        //当前节点前后引用为null ，保证gc
        head.next = null ; head.prev = null ; head.bucket = null ;
        return head ;
    }
}
